package com.xbongbong.saas.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.pro.enums.fund.enums.ModelTypeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.domain.entity.CustomerStatementEntity;
import com.xbongbong.saas.domain.entity.CustomerStatementProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.enums.CustomerStatementEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.product.ContractOutstockProductEnum;
import com.xbongbong.saas.model.CustomerStatementModel;
import com.xbongbong.saas.model.CustomerStatementProductModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: 汪腾伟
 * @date: Created in 2021/9/10 17:52
 * @description： 对账单helper
 */
@Component
public class SaasCustomerStatementHelper {

    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private CustomerStatementModel customerStatementModel;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private CustomerStatementProductModel customerStatementProductModel;
    @Resource
    private FundHelp fundHelp;
    private static final Logger LOG = LoggerFactory.getLogger(InitDataHelp.class);

    /**
     * 客户对帐单保存
     * 注：
     * 1、如果entityList内的实体del=1，则不生成其对账记录
     * 2、只有回款单、应收款才会生成对账流水
     * 3、回款计划、销项发票、销售出库单/出库发货单（根据应收方式不同）会产生应收，但它们本身不入对账记录
     * @param businessType 回款单、应收款、出库单（一般情况下只有前两种，只有出库产生应收才会传入出库单类型，因为要基于这个判断是否处理产品。但是入对账流水表的BUSINESS_TYPE还是应收款）
     * @param explainMap 表单解释map
     * @param entityList 回款单or应收款list
     * @param distributorMark 经销商标识
     * @return
     * @throws XbbException
     */
    public void save(Integer businessType, Map<String, FieldAttrEntity> explainMap, List<? extends PaasFormDataEntityExt> entityList, Integer distributorMark) throws XbbException {
        if(CollectionsUtil.isNotEmpty(entityList)){
            String corpid = entityList.get(0).getCorpid();
            List<CustomerStatementEntity> customerStatementList = new ArrayList<>();
            if(Objects.equals(businessType, XbbRefTypeEnum.PAYMENT.getCode())){
                customerStatementList = insertStatement4Payment(entityList, explainMap);
            }else if(Objects.equals(businessType,XbbRefTypeEnum.PAYMENT_SHEET.getCode())){
                customerStatementList = insertStatement4Sheet(entityList, explainMap);
            }else if(Objects.equals(businessType,XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())){
                customerStatementList = insertStatement4Outstock(entityList, explainMap);
            }
            if (customerStatementList.size() > 0) {
                // 为了加个关联产品，app_id,menu_id,form_id都要保存
                PaasFormEntityExt paasFormEntityExt = paasFormModel.getByBusinessType4Distributor(XbbRefTypeEnum.CUSTOMER_STATEMENT.getCode(), corpid, distributorMark, null);
                for (CustomerStatementEntity customerStatementEntity : customerStatementList) {
                    customerStatementEntity.setAppId(paasFormEntityExt.getAppId());
                    customerStatementEntity.setMenuId(paasFormEntityExt.getMenuId());
                    customerStatementEntity.setFormId(paasFormEntityExt.getId());
                }
                customerStatementModel.insertBatch(customerStatementList);
                List<CustomerStatementProductEntity> productEntityList = new LinkedList<>();
                if (Objects.equals(businessType,XbbRefTypeEnum.CONTRACT_OUTSTOCK.getCode())) {
                    // 保存关联产品相关数据
                    for (CustomerStatementEntity customerStatementEntity : customerStatementList) {
                        JSONObject data = customerStatementEntity.getData();
                        Long sourceId = data.getLong(CustomerStatementEnum.SOURCE_ID.getAttr());
                        if (CollectionsUtil.isNotEmpty(data.getJSONArray(CustomerStatementEnum.PRODUCT.getAttr()))) {
                            // 存在产品时，产品数据单独存在tb_saas_customer_statement_product中
                            OutstockEntityExt outstockEntityExt = outstockModel.getByKey(sourceId, corpid);
                            if (Objects.isNull(outstockEntityExt)) {
                                continue;
                            }
                            List<OutstockProductEntity> outstockProducts = outstockProductModel.getProductsByOutstockIdIn(corpid, Collections.singletonList(outstockEntityExt.getId()));
                            for (OutstockProductEntity outstockProduct : outstockProducts) {
                                CustomerStatementProductEntity productEntity = new CustomerStatementProductEntity(corpid, 0);
                                productEntity.setStatementId(customerStatementEntity.getId());
                                BeanUtil.copyProperties(outstockProduct, productEntity);
                                productEntity.setId(null);
                                productEntityList.add(productEntity);
                            }
                        }
                    }
                    if (CollectionsUtil.isNotEmpty(productEntityList)) {
                        customerStatementProductModel.insertBatch(productEntityList);
                    }
                }
            }
        }
    }

    /**
     * 应收款进入对账单，插入list封装
     * @param entityList
     * @return java.util.List<com.xbongbong.saas.domain.entity.CustomerStatementEntity>
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private List<CustomerStatementEntity> insertStatement4Payment(List<? extends PaasFormDataEntityExt> entityList, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        List<CustomerStatementEntity> customerStatementList = new ArrayList<>();
        String timeAttr = PaymentEnum.ESTIMATE_TIME.getAttr();
        FieldAttrEntity timeAttrEntity = explainMap.get(timeAttr);
        for(PaasFormDataEntityExt paasFormDataEntity : entityList){
            if (Objects.equals(paasFormDataEntity.getDel(), DelEnum.DELETE.getDel())) {
                continue;
            }
            JSONObject data = paasFormDataEntity.getData();
            JSONObject customerStatementData = new JSONObject();
            CustomerStatementEntity customerStatementEntity = getCustomerStatementByPayment(timeAttr, timeAttrEntity, paasFormDataEntity, data, customerStatementData);
            customerStatementEntity.setData(customerStatementData);
            customerStatementList.add(customerStatementEntity);
        }
        return customerStatementList;
    }

    /**
     * 回款单进入对账单，插入list封装
     * @param entityList
     * @return java.util.List<com.xbongbong.saas.domain.entity.CustomerStatementEntity>
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private List<CustomerStatementEntity> insertStatement4Sheet(List<? extends PaasFormDataEntityExt> entityList, Map<String, FieldAttrEntity> explainMap) throws XbbException {
        List<CustomerStatementEntity> customerStatementList = new ArrayList<>();
        String timeAttr = PaymentSheetEnum.PAYMENT_TIME.getAttr();
        FieldAttrEntity timeAttrEntity = explainMap.get(timeAttr);
        for(PaasFormDataEntityExt paasFormDataEntity : entityList){
            if (Objects.equals(paasFormDataEntity.getDel(), DelEnum.DELETE.getDel())) {
                continue;
            }
            JSONObject customerStatementData = new JSONObject();
            CustomerStatementEntity customerStatementEntity = getCustomerStatementBySheet(timeAttr, timeAttrEntity, paasFormDataEntity, customerStatementData);
            customerStatementEntity.setData(customerStatementData);
            customerStatementList.add(customerStatementEntity);
        }
        return customerStatementList;
    }

    /**
     * 按出库模式产生的对账流水
     * @param entityList 虽然是出库产生应收，但是本质还是用出库生成的应收款来生成对账单，即该list为应收款list
     * @param explainMap 应收款解释
     * @return
     */
    private List<CustomerStatementEntity> insertStatement4Outstock(List<? extends PaasFormDataEntityExt> entityList, Map<String, FieldAttrEntity> explainMap) throws XbbException{
        List<CustomerStatementEntity> customerStatementList = new ArrayList<>();
        String timeAttr = PaymentEnum.ESTIMATE_TIME.getAttr();
        FieldAttrEntity timeAttrEntity = explainMap.get(timeAttr);
        for(PaasFormDataEntityExt paasFormDataEntity : entityList){
            if (Objects.equals(paasFormDataEntity.getDel(), DelEnum.DELETE.getDel())) {
                continue;
            }
            JSONObject data = paasFormDataEntity.getData();
            JSONObject customerStatementData = new JSONObject();
            CustomerStatementEntity customerStatementEntity = getCustomerStatementByPayment(timeAttr, timeAttrEntity, paasFormDataEntity, data, customerStatementData);
            //处理其它费用，产品
            Double otherExpense = FastJsonHelper.getDoubleFromFormData(data, BasicConstant.STATEMENT_OTHER_EXPENSE);
            customerStatementData.put(CustomerStatementEnum.OTHER_EXPENSE.getAttr(), otherExpense);
            JSONArray products = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.STATEMENT_PRODUCT,new JSONArray());
            JSONArray idIn = new JSONArray();
            for (int i = 0, size=products.size(); i < size; i++) {
                JSONObject product = products.getJSONObject(i);
                idIn.add(product.getString(ContractOutstockProductEnum.PRODUCT.getAttr()));
            }
            customerStatementData.put(CustomerStatementEnum.PRODUCT.getAttr(), idIn);
            customerStatementEntity.setData(customerStatementData);
            customerStatementList.add(customerStatementEntity);
        }
        return customerStatementList;
    }

    /**
     * 通过应收款生成的对账单
     * （1）直接生成应收款时，再生成对账单，比如新建红冲应收款时
     * （2）根据应收规则(手动创建应收/按开票产生应收/按出库产生应收)生成应收款后，再基于应收款生成对账单，而不是用来源单据本身直接生成对账单流水
     * @param timeAttr 应收款的预计回款日期字段attr
     * @param timeAttrEntity 应收款的预计回款日期字段实体
     * @param paasFormDataEntity 应收款实体
     * @param data 应收款data
     * @param customerStatementData 对账单流水data
     * @return com.xbongbong.saas.domain.entity.CustomerStatementEntity
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private CustomerStatementEntity getCustomerStatementByPayment(String timeAttr, FieldAttrEntity timeAttrEntity, PaasFormDataEntityExt paasFormDataEntity, JSONObject data, JSONObject customerStatementData) {
        CustomerStatementEntity customerStatementEntity = new CustomerStatementEntity();
        customerStatementEntity.setCorpid(paasFormDataEntity.getCorpid());
        customerStatementData.put(CustomerStatementEnum.STATEMENT_ID.getAttr(), paasFormDataEntity.getId());
        customerStatementData.put(CustomerStatementEnum.STATEMENT_NO.getAttr(), paasFormDataEntity.getSerialNo());
        Long modelType = paasFormDataEntity.getSysLong10();
        //实体的创建时间
        Long addTime = Objects.isNull(paasFormDataEntity.getAddTime()) ? DateTimeUtil.getInt() : paasFormDataEntity.getAddTime();
        if (Objects.isNull(modelType)) {
            modelType = ModelTypeEnum.PLAN.getCode();
        }
        customerStatementEntity.setSysLong10(modelType);
        customerStatementEntity.setAddTime(addTime);
        customerStatementEntity.setUpdateTime(addTime);
        customerStatementEntity.setSysLong1(XbbRefTypeEnum.PAYMENT.getCode());
        customerStatementEntity.setSysLong2(paasFormDataEntity.getId());
        customerStatementEntity.setDel(DelEnum.NORMAL.getDel());
        Long sheetTime = addTime;
        try {
            sheetTime = fundHelp.getSheetTime4FlowAndStatement(data, timeAttr, timeAttrEntity, addTime);
        } catch (Exception e) {
            LOG.error("error payment Id :"+paasFormDataEntity.getId()+"addTime error" + e, e);
        }
        customerStatementData.put(CustomerStatementEnum.CHECKING_DATE.getAttr(), sheetTime);
        customerStatementData.put(CustomerStatementEnum.BUSINESS_TYPE.getAttr(), XbbRefTypeEnum.PAYMENT.getCode());
        customerStatementData.put(CustomerStatementEnum.CUSTOMER_ID.getAttr(), data.getLongValue(PaymentEnum.CUSTOMER.getAttr()));
        customerStatementData.put(CustomerStatementEnum.CUSTOMER_NAME.getAttr(), data.getString(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr()) == null ? "" : data.getString(PaymentEnum.CUSTOMER_LINK_TEXT.getAttr()));
        customerStatementData.put(CustomerStatementEnum.CONTRACT_ID.getAttr(), data.getLongValue(PaymentEnum.CONTRACT.getAttr()));
        customerStatementData.put(CustomerStatementEnum.CONTRACT_NO.getAttr(), data.getString(PaymentEnum.CONTRACT_LINK_TEXT.getAttr()) == null ? "" : data.getString(PaymentEnum.CONTRACT_LINK_TEXT.getAttr()));
        //手动创建应收时来源单据为空
        Integer sourceRefType = data.getInteger(PaymentEnum.SOURCE_REF_TYPE.getAttr());
        if (Objects.nonNull(sourceRefType) && sourceRefType > 0) {
            customerStatementData.put(CustomerStatementEnum.SOURCE_TYPE.getAttr(), sourceRefType);
            customerStatementData.put(CustomerStatementEnum.SOURCE_ID.getAttr(), data.getLong(PaymentEnum.SOURCE.getAttr()));
            customerStatementData.put(CustomerStatementEnum.SOURCE_NO.getAttr(), data.getString(PaymentEnum.SOURCE_LINK_TEXT.getAttr()));
        }
        customerStatementData.put(CustomerStatementEnum.AMOUNT_RECEIVABLE.getAttr(), data.getDoubleValue(PaymentEnum.AMOUNT.getAttr()));
        return customerStatementEntity;
    }


    /**
     * 通过回款单生成的对账单
     * @param timeAttr 回款单的回款日期字段attr
     * @param timeAttrEntity 回款单回款日期字段实体
     * @param paasFormDataEntity 回款单实体
     * @param customerStatementData 对账单流水data
     * @return com.xbongbong.saas.domain.entity.CustomerStatementEntity
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    private CustomerStatementEntity getCustomerStatementBySheet(String timeAttr, FieldAttrEntity timeAttrEntity, PaasFormDataEntityExt paasFormDataEntity, JSONObject customerStatementData) throws XbbException {
        CustomerStatementEntity customerStatementEntity = new CustomerStatementEntity();
        customerStatementEntity.setCorpid(paasFormDataEntity.getCorpid());
        customerStatementData.put(CustomerStatementEnum.STATEMENT_ID.getAttr(),paasFormDataEntity.getId());
        customerStatementData.put(CustomerStatementEnum.STATEMENT_NO.getAttr(),paasFormDataEntity.getSerialNo());
        Long modelType = paasFormDataEntity.getSysLong10();
        if (Objects.isNull(modelType)) {
            modelType = ModelTypeEnum.PLAN.getCode();
        }
        customerStatementEntity.setSysLong10(modelType);
        //实体的创建时间
        Long addTime = Objects.isNull(paasFormDataEntity.getAddTime()) ? DateTimeUtil.getInt() : paasFormDataEntity.getAddTime();
        customerStatementEntity.setAddTime(addTime);
        customerStatementEntity.setUpdateTime(addTime);
        customerStatementEntity.setSysLong1(XbbRefTypeEnum.PAYMENT_SHEET.getCode());
        customerStatementEntity.setSysLong2(paasFormDataEntity.getId());
        customerStatementEntity.setDel(DelEnum.NORMAL.getDel());
        JSONObject data = paasFormDataEntity.getData();
        Long sheetTime = addTime;
        try {
            sheetTime = fundHelp.getSheetTime4FlowAndStatement(data, timeAttr, timeAttrEntity, addTime);
        } catch (Exception e) {
            LOG.error("error sheet Id :"+paasFormDataEntity.getId()+"time error" + e, e);
        }
        customerStatementData.put(CustomerStatementEnum.CHECKING_DATE.getAttr(), sheetTime);
        customerStatementData.put(CustomerStatementEnum.BUSINESS_TYPE.getAttr(), XbbRefTypeEnum.PAYMENT_SHEET.getCode());
        customerStatementData.put(CustomerStatementEnum.TYPE.getAttr(), data.getString(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()));
        customerStatementData.put(CustomerStatementEnum.CUSTOMER_ID.getAttr(), data.getLongValue(PaymentSheetEnum.CUSTOMER_ID.getAttr()));
        customerStatementData.put(CustomerStatementEnum.CUSTOMER_NAME.getAttr(), FastJsonHelper.getStringOrDefaultFromFormData(data,PaymentSheetEnum.CUSTOMER_NAME_LINK_TEXT.getAttr(),""));

        JSONArray contractArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,PaymentSheetEnum.CONTRACT.getAttr(),new JSONArray());
        JSONArray contractLinkArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(data,PaymentSheetEnum.CONTRACT_LINK_TEXT.getAttr(),new JSONArray());
        if(contractArray.size() > BasicConstant.ZERO){
            customerStatementData.put(CustomerStatementEnum.CONTRACT_ID.getAttr(), contractArray.getLong(BasicConstant.ZERO));
        }
        if(contractLinkArray.size() > BasicConstant.ZERO){
            customerStatementData.put(CustomerStatementEnum.CONTRACT_NO.getAttr(), contractLinkArray.getString(BasicConstant.ZERO));
        }
        //回款金额
        customerStatementData.put(CustomerStatementEnum.AMOUNT_RECEIVED.getAttr(), data.getDoubleValue(PaymentSheetEnum.AMOUNT.getAttr()));
        //核销金额
        customerStatementData.put(CustomerStatementEnum.WRITE_OFF_AMOUNT.getAttr(), data.getDoubleValue(PaymentSheetEnum.WRITE_OFF_AMOUNT.getAttr()));
        return customerStatementEntity;
    }
}
